Improve paywall loading performance and fix concurrency issues - #453
Merged
Conversation
…nd rule evaluation - Publish config as Retrieved immediately after ApplyConfig; run product warm-up and enrichment resolution in the background instead of gating every presentation on them - Run configure()'s config fetch and identity setup concurrently - Fast-path implicit triggers that map to no placement so app_launch/ session_start no longer head-of-line block register() on the serial queue - Await entitlements and config concurrently in the presentation pipeline - Sync subscription status without gating local Play queries on config; await billing connection instead of fixed retry sleeps; query SUBS and INAPP purchases and product details concurrently - Make PaywallRequestManager dedup thread-safe (ConcurrentHashMap with atomic in-flight claim) and fire lifecycle analytics without blocking the load path - Diff config refreshes by paywall cacheKey and evict only changed paywalls from the response cache; invalidate the preload fingerprint on refresh changes and fresh assignments so re-preload actually runs - Make PaywallViewCache synchronous (removes fire-and-forget writes and runBlocking reads on a multi-threaded dispatcher) - Only treat main-frame webview errors as page failures; subresource failures no longer restart the page or count toward fallback attempts; bounded main-frame retry now works on API 26+ - Animate shimmer via view alpha on a hardware layer instead of re-rasterizing a software-layer vector every frame - Use the fixed default duration for the popup entrance animation and apply presentation.delay only to the initial reveal, not the post-purchase spinner - Build the rule-evaluation base context once per evaluation pass while resolving computed properties fresh per rule - Count trigger rule occurrences with SQL COUNT instead of materializing rows; give event-data inserts their own serial lane - Construct log strings lazily on the paywall hot path Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MCNtq6WEfD6su3SjFuhfHV
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MCNtq6WEfD6su3SjFuhfHV
- Serialize lifecycle analytics on a single lane so start/complete event pairs keep their order; guard against zombie fetches from cancelled callers; close the double-fetch window in saveRequestHash; skip stale cache writes when the request cache was invalidated mid-flight - Bound-await enrichment (1s) before publishing config as Retrieved so fresh installs don't evaluate audience filters without enrichment - Await a valid config before starting the 30s assignments timeout so a slow config fetch can't permanently skip the initial assignment restore - Retry the config wait once after entitlements resolve so the concurrent waits never tolerate less config latency than the old sequential path - Track billing connection as Connecting/Connected/Failed so restores fail fast when billing can never connect; defer Inactive status until config has been applied or failed so test mode is respected - Record main-frame webview errors synchronously so the load retry cap can't be reset by the failed load's own onPageFinished; treat failures of the paywall runtime bundle as page-level again so fallback URLs still engage; report the failing resource's URL in resource-load events - Build shared rule-evaluation attributes lazily and contain their failures so attribute errors degrade to no-match instead of aborting the presentation Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MCNtq6WEfD6su3SjFuhfHV
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes in this pull request
This PR significantly improves paywall loading performance and fixes several concurrency-related issues:
Performance Enhancements
configure()now runs config fetching and identity setup concurrently instead of sequentially, reducing startup timewaitForEntitlementsAndConfignow waits for both entitlements and config concurrently, with proper timeout handling prioritizing entitlements failuresConcurrency and Thread Safety Fixes
PaywallRequestManager: Converted from single-threaded actor pattern to multi-threaded IO dispatcher with thread-safe collections:
MutableMapwithConcurrentHashMapforactiveTasksandpaywallsByHashAtomicLongfor cache generation tracking to prevent stale writestrackScopefor lifecycle event tracking to maintain orderingputIfAbsentandremove(key, value)AutomaticPurchaseController: Improved connection state management:
isConnectedwith tri-stateConnectionStateenum (Connecting/Connected/Failed)CONNECTION_TIMEOUT_MSconstant for explicit timeout handlingGoogleBillingWrapper: Enhanced concurrent query handling with atomic operations and proper timeout management
PaywallViewCache: Removed blocking
runBlockingcalls and single-threaded dispatcher:_activePaywallVcKeyvolatile for safe concurrent accessCoreDataManager: Separated event data persistence into dedicated coroutine lane to prevent blocking other database operations
Bug Fixes
MAX_LOAD_RETRIESconstantAPI Changes
evaluateExpression()that acceptssharedAttributesparameter for CEL evaluationinvalidatePreloadFingerprint()method to clear cache on config refreshresetPaywallRequestCache(identifiers)for selective cache invalidationTesting
SuperscriptEvaluatorTestfor computed property overlayingChecklist
CHANGELOG.mdwith enhancements and bug fixeshttps://claude.ai/code/session_01MCNtq6WEfD6su3SjFuhfHV